using System;
using System.Collections.Generic;
using System.Text;
using WCFDicing.DataContracts;
using WCFDicing.BusinessEntities;
using Physics;
using System.Threading;
//ok

namespace WCFDicing.BusinessLogic
{
    /// <summary>
    /// klasa obslugujaca gre w kosci na stole
    /// </summary>
    public class DicingGame
    {
        #region synchro

        //delete when THE BEST PROGGRAME IN THE WORLD will write duplex webservices
        /// <summary>
        /// data ostatniego polaczenia sie aktualnego grajacego
        /// </summary>
        private DateTime last_actual_player_connection;


        /// <summary>
        /// funkcja aktualizujaca ostatni czas polaczenia sie klienta
        /// oraz sprawdza czy klient utrzymuje polaczenie z gra 
        /// </summary>
        /// <param name="ID"></param>
        private void CheckIsAlive( int ID )
        {
            if ( ID == table.PlayerBidId )
            {
                last_actual_player_connection = DateTime.Now;
            }
            else
            {
                TimeSpan time_expired = DateTime.Now.Subtract( last_actual_player_connection );
                if ( time_expired.Minutes > 1 )
                {
                    EndGame( table.PlayerBidId );
                    last_actual_player_connection = DateTime.Now;
                }
            }
        }


        //
        #endregion

        /// <summary>
        /// nazwa bazy danych
        /// </summary>
        static string DataBasePath = "CasinoDB";

        /// <summary>
        /// obiekt operujacy na bazie danych
        /// </summary>
        CasinoUsersManager userManager = new CasinoUsersManager( DataBasePath );

        /// <summary>
        /// nazwa gry
        /// </summary>
        private string name;

        /// <summary>
        /// get i set nazwy gry
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// stol gry w kosci
        /// </summary>
        private DicingTable table;

        /// <summary>
        /// get stol do gry w kosci
        /// </summary>
        public DicingTable Table
        {
            get { return table; }
        }




        #region konstruktor
        /// <summary>
        /// domyslny konstruktor tworzacy domyslny stol
        /// </summary>
        public DicingGame()
        {
            this.table = new DicingTable( new DicingRoomOption( ) );
            this.name = "domyslny stol";
        }

        /// <summary>
        /// konstruktor z opcjami
        /// </summary>
        /// <param name="opt">opcje gry</param>
        public DicingGame( DicingRoomOption opt )
        {
            this.table = new DicingTable( opt );
            this.name = "domyslny stol";
        }

        /// <summary>
        /// konstruktor z opcjami i nadana nazwa
        /// </summary>
        /// <param name="opt">opcje gry</param>
        /// <param name="name">nazwa gry</param>
        public DicingGame( DicingRoomOption opt, string name )
        {
            this.table = new DicingTable( opt );
            this.name = name;
        }

        #endregion

        /// <summary>
        /// obsluguje zakonczenie gry dla gracza
        /// </summary>
        /// <param name="ID">id gracza ktory skonczyl/odlacza sie</param>
        /// <returns>czy operacja sie udala</returns>
        public bool EndGame( int ID )
        {
            //sprawdza czy gracz istnieje
            if ( !table.Players.ContainsKey( ID ) )
                return false;

            ////////////////zmien gdy podlaczysz DB
            //uaktualniamy stan konta
            //userManager.UpdateUserMoney( new CASINO_USER_MONEY( ID, table.Players[ID].MoneyField ) );

            //leave ze stolu
            return table.Leave( ID );
        }

        /// <summary>
        /// obsluga przylaczenia gracza do gry 
        /// </summary>
        /// <param name="player">gracz podlaczany</param>
        /// <returns>czy operacja sie udala</returns>
        public bool Join( DicingPlayer player )
        {
            //sprawdzamy czy trwa gra
            if ( table.TableAction != DicingActionList.FirstRound && table.TableAction != DicingActionList.NewRound )
                return false;

            //sprawdzamy czy nie laczy sie ten sam
            if(IsPlaying(player.PlayerId))
                return false;

            //join ze stolu
            return table.Join( player );
        }

        /// <summary>
        /// sprawdza czy dany gracz gra na tym stole
        /// </summary>
        /// <param name="ID">id gracza sprawdzanego</param>
        /// <returns>czy gracz gra na stole</returns>
        public bool IsPlaying( int ID )
        {
            return table.Players.ContainsKey( ID );
        }

        /// <summary>
        /// obsluga obstawienia przez gracza
        /// </summary>
        /// <param name="betSize">stawka zakladu</param>
        /// <param name="ID">id gracza obstawiajacego</param>
        /// <returns>czy operacja sie udala</returns>
        public bool Bet( int betSize, int ID )
        {
            if ( !table.Players.ContainsKey( ID ) ) //czy gracz istnieje
                return false;
            else if ( betSize > table.Options.MaximumBet )      //czy nie obstawia za duzo
                return false;
            else if ( ID != table.PlayerBidId )                 //czy gracz moze w tej chwili obstawic
                return false;
            else
                return table.Bet( betSize );                    //obstawiamy

        }

        /// <summary>
        /// funkcja pobierajaca stol
        /// </summary>
        /// <param name="ID">id gracza ktory wywolal funckje</param>
        /// <returns>stol do gry w kosci z serwera</returns>
        public DicingTable GetTable( int ID )
        {
            CheckIsAlive( ID );                 
            return new DicingTable( table );    //bez zabezpieczen bo nie mam co zabezpieczac ;)
        }

        /// <summary>
        /// funkcja zapoczatkowania rozgrywki
        /// </summary>
        /// <returns>czy operacja sie powiodla</returns>
        public bool Begin()
        {
            //robimy tylko wtedy gdy gra ma odpowiedni status
            if ( table.TableAction != DicingActionList.FirstRound && table.TableAction != DicingActionList.NewRound )
                return false;
            else if ( table.Players.Count < 2 )     //czy jest z kim grac
                return false;
            else
            {
                return table.Begin( );
            }
        }

        /// <summary>
        /// obsluga nastepnego rzutu
        /// </summary>
        /// <param name="id">id gracza ktory chce rzucic</param>
        /// <param name="animation">parametry rzutu</param>
        /// <returns>rezultat rzutu</returns>
        public DicingResult NextThrow(int id,  DicingAnimation animation )
        {
            //sprawdzamy czy odpowiedni stan stolu
            if ( !( table.TableAction == DicingActionList.Throwing || table.TableAction == DicingActionList.Aiming ) )
                return new DicingResult( );

            

            ////////////////////////////////fizyka sebastiana
            //dokonujemy symulacji
            DiceSimulation sim = new DiceSimulation( );
            //int t1 = Environment.TickCount;
            DiceResult diceResult = sim.ComputeResult( new MyMath.MyVector( animation.X, animation.Y, animation.Z )
                , ( float ) animation.Valicity );
            //int dt = Environment.TickCount - t1;
            //Thread.Sleep( ( int ) ( 1000 * sim.AnimationTime ) - dt );
            DicingResult result = new DicingResult( diceResult.dice1, diceResult.dice2 );

            //aktualizujemy dane na stole
            table.Animation = new DicingAnimation( animation );
            table.Result = new DicingResult(result);

            //uruchamiamy silnik obslugi regul gry
            RulesEngine( result.Dice1 + result.Dice2 );

            return result;
        }


        /// <summary>
        /// obluga przepisow gry po dokonanym rzucie
        /// </summary>
        /// <param name="dice">ilosc wyrzuconych oczek</param>
        private void RulesEngine( int dice )
        {
            //jesli byl to pierwszy rzut
            if ( table.Players[table.PlayerThrowId].CurrentAction == DicingActionList.Throwing )
            {
                if ( dice == 7 || dice == 11 )      //7 i 11 wygrywa
                    table.WinThrow( );
                else if ( dice == 2 || dice == 3 || dice == 12 )    //2, 3, 12 przegrywa
                    table.LostThrow( );
                else
                {
                    //w przeciwnym wypadku gracz celuje
                    table.Aim = dice;
                    table.Players[table.PlayerThrowId].Aim = dice;
                    table.Players[table.PlayerThrowId].CurrentAction = DicingActionList.Aiming;
                    table.Players[table.PlayerThrowId].CurrentThrowNo = 0;
                    table.TableAction = DicingActionList.Aiming;
                }
            }
            else if ( table.Players[table.PlayerThrowId].CurrentAction == DicingActionList.Aiming )
            {
                //gdy byl to rzut "celujacy"
                if ( dice == table.Aim )
                    table.WinThrow( );  //gdy trafil wygral!
                else if ( dice == 7 )
                    table.LostThrow( );     //gdy trafil w 7 przegral
                else
                {   
                    //nie trafil zwiekszamy ilosc prob
                    table.Players[table.PlayerThrowId].CurrentThrowNo++;
                    //sprawdzamy czy nie przekroczyl limitu
                    if ( table.Players[table.PlayerThrowId].CurrentThrowNo >= table.Options.ChanceCount )
                        table.LostThrow( ); //jesli przekroczyl przegral
                }

            }
        }



    }
}
